The Kinetis SDK provides the abstraction layer for real-time operating systems.
More...
Overview
Operating System Abstraction layer (OSA) provides a common set of services for drivers and applications so that they can work with or without the operating system. OSA provides services that abstract most of the OS kernel functionality. These services can either be mapped to the target OS functions directly, or implemented by OSA when no OS is used (bare metal) or when the service does not exist in the target OS. Freescale Kinetis SDK implements the OS abstraction layer for the Freescale MQX RTOS, FreeRTOS, µC/OS, and for no OS usage (bare metal). The bare metal OS abstraction implementation is selected as the default option.
OSA provides these services: task management, semaphore, mutex, event, message queue, memory allocator, critical section, and time delay.
Task Management
With OSA, applications can create and destroy tasks dynamically. These services are mapped to the task functions of RTOSes. For bare metal, a function poll mechanism is used to simulate a task.
To create a task, use the
FSL_RTOS_TASK_DEFINE() to declare the task statically. Then, use the
task_create() to create the task.
This is an example code to creating and destroying a task:
Semaphore
OSA provides the drivers and applications with a counting semaphore. It can be used either to synchronize tasks or to synchronize a task and an ISR.
To use the semaphore, use the
sync_object_declare() and the
sync_create() to create it. The object can be created with an initial value.
Depending on the target OS, the
sync_object_declare() may either define or declare the object to be used by the
sync_create(). When the
sync_object_declare() defines the object with the memory allocated, the memory has be to available for the entire lifespan of the object. It is recommended to declare objects in places where the memory allocated has the desired scope. When the sync object is not used any more, use the
sync_destroy() to destroy it.
This is an example code to create and destroy a sync object:
There are two ways to wait for the sync object.
- The first way to wait for the sync object involves using the function, fsl_rtos_status sync_wait,(sync_object_t *obj, uint32_t timeout). This function waits for a timeout in milliseconds. Setting a parameter timeout as the kSyncWaitForever causes the thread to wait infinitely if the object can't be obtained. Note that the parameter timeout must not be 0.
- The second way to wait for the sync object involves using the function, fsl_rtos_status sync_poll(sync_object_t *obj), as a non-blocking interface.
To post the object, use either the
sync_signal() or the
sync_signal_from_isr().
Mutex
A mutex is used for mutual exclusion of the tasks when they access a shared resource.
Depending on the target OS, the
lock_object_declare() may either define or declare the object to be used by the
lock_create(). When the
lock_object_declare() defines the object with memory allocated, the memory has be to available for the entire lifespan of the object. It is recommended to declare objects in places where the memory allocated has the desired scope. You should use the
lock_object_declare() and the
lock_create() to create the object, and the
lock_destroy() to destroy it. When the lock object is created, it is in an unlocked state.This is example code to create and destroy a lock object:
There are two ways to wait for the lock object.
- The first way to wait for the lock object involves the function fsl_rtos_status lock_wait(lock_object_t *obj, uint32_t timeout). This function waits for the timeout in milliseconds. Setting a parameter timeout as the kSyncWaitForever makes the thread wait infinitely if the lock can't be obtained. Note that the parameter timeout must not be 0.
- The other way to wait for the lock object involves the function, fsl_rtos_status lock_poll(lock_object_t *obj), as a non-blocking interface.
To unlock the object, use the
lock_release().
Event
An event is supported with a single consumer and multi-producers.
The function fsl_rtos_status
event_create(event_object_t *obj, event_clear_type clearType) creates two types of event objects, auto-clear and manual-clear.
- An auto-clear event means that the event flags are cleared automatically.
- A manual-clear event means that applications must clear the flags manually.
The function fsl_rtos_status
event_wait(event_object_t *obj, uint32_t timeout, event_group_t *setFlags) waits for a timeout in milliseconds if the event flags are not set. Passing the
kSyncWaitForever causes it to wait forever. The event flags which are set can be obtained by the parameter setFlags. This interface does not have the parameter to specify which flags to wait for and will wait for any flag.
The functions fsl_rtos_status
event_set(event_object_t *obj, event_group_t flags) and fsl_rtos_status
event_set_from_isr(event_object_t *obj, event_group_t flags) set the event flags.
The function fsl_rtos_status
event_clear(event_object_t *obj, event_group_t flags) clears specified flags manually.
The function event_status
event_check_flags(event_object_t *obj, event_group_t flag) checks whether any of the specified flags are set.
When the event object is not used any more, use the event_destory to destroy it.
Message Queue
A message queue transfers messages between tasks. OSA provides two types of message queue.
- The first message queue occurs when only the pointer to the message is stored in the queue. The senders put pointer to the message in the queue and the receivers get the message through the pointer. This type of message queue is more efficient because it does not need to copy memories. Applications and drivers must ensure that the message is always valid until receivers get it. If not, use the second message queue type.
- The second message queue type occurs when entities are copied to the internal memory of the queue. Even though this is a safer approach, it slows down the performance.
Configure the macro __FSL_RTOS_MSGQ_COPY_MSG__ to determine which mode is used.
To create a message queue, use the
MSG_QUEUE_DECLARE() and the
msg_queue_create() like this:
The function fsl_rtos_status
msg_queue_put(msg_queue_handler_t handler, msg_queue_item_t item) puts the message to the queue. Depending on the target OS, the
MSG_QUEUE_DECLARE() may either define or declare the message queue to be used by the
msg_queue_create(). When the
MSG_QUEUE_DECLARE() defines the message queue with memory allocated, the memory has be to available for the entire lifespan of the message queue. It is recommended to declare the message queue in places where the memory allocated has the desired scope. If the queue is full, an error returns.
The function fsl_rtos_status
msg_queue_get(msg_queue_handler_t handler, msg_queue_item_t *item, uint32_t timeout) waits for a timeout to get the message if the queue is empty. Passing 0 causes it to return immediately and passing the
kSyncWaitForever causes it to wait forever.
The function fsl_rtos_status
msg_queue_flush(msg_queue_handler_t handler) cleans all messages in the queue.
If the queue is not used any more, use the
msg_queue_destroy() to destroy it.
Critical Section
The
rtos_enter_critical() and
rtos_exit_critical() functions ensure that code is not pre-empted.
Dynamic Memory Allocation
The void *mem_allocate(size_t size) function allocates memory with specified size. The void *mem_allocate_zero(size_t size) function allocates and cleans the memory. The fsl_rtos_status
mem_free(void *ptr) function frees the memory. For RTOSes that have internal memory manager, such as the Freescale MQX RTOS, OSA maps these functions directly. For other RTOSes or for bare metal, the standard functions malloc/calloc/free are used.
Time Delay
The function void
time_delay(uint32_t delay) delays specified time in milliseconds.